package com.hck.taozi_help.utils.permission.core;



import static com.hck.taozi_help.utils.permission.utils.Utils.getActivity;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Fragment;
import android.content.pm.PackageManager;
import android.os.Build;


import com.hck.taozi_help.utils.permission.annotations.PermissionDenied;
import com.hck.taozi_help.utils.permission.annotations.PermissionGranted;
import com.hck.taozi_help.utils.permission.annotations.PermissionStatistics;
import com.hck.taozi_help.utils.permission.utils.Utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

public class PermissionHelper {
    private String[] mPermissions;
    private int mRequestCode;
    private Object object;

    private PermissionHelper(Object object) {
        this.object = object;
    }

    public static PermissionHelper with(Activity activity) {
        return new PermissionHelper(activity);
    }

    public static PermissionHelper with(Fragment fragment) {
        return new PermissionHelper(fragment);
    }

    public PermissionHelper permissions(String... permissions) {
        this.mPermissions = permissions;
        return this;
    }

    public PermissionHelper addRequestCode(int requestCode) {
        this.mRequestCode = requestCode;
        return this;
    }

    @TargetApi(value = Build.VERSION_CODES.M)
    public void request() {
        requestPermissions(object, mRequestCode, mPermissions);
    }

    public static void needPermission(Activity activity, int requestCode, String[] permissions) {
        requestPermissions(activity, requestCode, permissions);
    }

    public static void needPermission(Fragment fragment, int requestCode, String[] permissions) {
        requestPermissions(fragment, requestCode, permissions);
    }

    public static void needPermission(Activity activity, int requestCode, String permission) {
        needPermission(activity, requestCode, new String[]{permission});
    }

    public static void needPermission(Fragment fragment, int requestCode, String permission) {
        needPermission(fragment, requestCode, new String[]{permission});
    }

    @TargetApi(value = Build.VERSION_CODES.M)
    private static void requestPermissions(Object object, int requestCode, String[] permissions) {
        HashSet<String> deniedPermissions = new HashSet<>();
        HashSet<String> passedPermissions = new HashSet<>();
        Utils.findDeniedPermissions(getActivity(object), deniedPermissions, passedPermissions, permissions);
        if (deniedPermissions.size() > 0) {
            if (Utils.isOverMarshmallow()) {
                if (object instanceof Activity) {
                    ((Activity) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
                } else if (object instanceof Fragment) {
                    ((Fragment) object).requestPermissions(deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
                }
            } else {
                statisticsPermission(object, requestCode, deniedPermissions, passedPermissions);
                doExecuteFail(object, requestCode, deniedPermissions);
            }
        } else {
            statisticsPermission(object, requestCode, deniedPermissions, passedPermissions);
            doExecuteSuccess(object, requestCode, passedPermissions);
        }
    }

    public static void onRequestPermissionsResult(Activity activity, int requestCode, String[] permissions,
                                                  int[] grantResults) {
        requestResult(activity, requestCode, permissions, grantResults);
    }

    public static void onRequestPermissionsResult(Fragment fragment, int requestCode, String[] permissions,
                                                  int[] grantResults) {
        requestResult(fragment, requestCode, permissions, grantResults);
    }

    private static void requestResult(Object obj, int requestCode, String[] permissions,
                                      int[] grantResults) {
        Set<String> passPermission = new HashSet<>();
        Set<String> deniedPermissions = new HashSet<>();
        for (int i = 0; i < grantResults.length; i++) {
            if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                deniedPermissions.add(permissions[i]);
            } else {
                passPermission.add(permissions[i]);
            }
        }

        //TODO 统计所有成功的失败的请求
        statisticsPermission(obj, requestCode, deniedPermissions, passPermission);

        if (deniedPermissions.size() > 0) {
            doExecuteFail(obj, requestCode, deniedPermissions);
        } else {
            doExecuteSuccess(obj, requestCode, passPermission);
        }
    }

    private static void statisticsPermission(Object obj, int requestCode, Set<String> deniedPermissions, Set<String> passPermission) {
        Method executeMethod = Utils.findMethodWithRequestCode(obj.getClass(), PermissionStatistics.class, requestCode);
        executeMethod(obj, executeMethod, deniedPermissions, passPermission);
    }

    private static void doExecuteSuccess(Object activity, int requestCode, Set<String> permissions) {
        Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(), PermissionGranted.class, requestCode);

        executeMethod(activity, executeMethod, permissions);
    }

    private static void doExecuteFail(Object activity, int requestCode, Set<String> permissions) {
        Method executeMethod = Utils.findMethodWithRequestCode(activity.getClass(), PermissionDenied.class, requestCode);
        executeMethod(activity, executeMethod, permissions);
    }

    private static void executeMethod(Object activity, Method executeMethod, Set<String>... permissions) {
        if (executeMethod != null) {
            try {
                if (!executeMethod.isAccessible()) executeMethod.setAccessible(true);
                executeMethod.invoke(activity, permissions);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
